package cn.xioabai.common.utility;

import cn.hutool.core.lang.Assert;
import cn.xioabai.common.enums.SqlKeyWordEnum;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * sql语句生成
 *
 * @Author yangdaji
 * @Date 2023/02/18
 * @PackageName cn.xiaobai.utils
 * @ClassName SqlGenerateUtils
 */
public class SqlGenerateUtils {

    /**
     * 生成指定sql语句
     *
     * @param cls            类对象
     * @param sqlKeyWordEnum sql 关键字
     * @param tableName      表名
     * @param isAllField     是否使用全表字段,否则使用*进行替代
     * @param conditionMap   条件数据
     * @param excludeField   排除的字段
     * @return
     */
    public static String generateSql(Class<?> cls, SqlKeyWordEnum sqlKeyWordEnum,
                                     String tableName, Boolean isAllField,
                                     Map<String, List<Object>> conditionMap,
                                     String... excludeField) {
        switch (sqlKeyWordEnum) {
            case SELECT:
                return selectSql(cls, sqlKeyWordEnum, tableName, isAllField, excludeField);
            case UPDATE:
                return updateSql(cls, sqlKeyWordEnum, tableName, excludeField);
            case INSERT:
                return insertSql(cls, sqlKeyWordEnum, tableName, excludeField);
            case DELETE:
                return deleteSql(sqlKeyWordEnum, tableName, conditionMap);
            default:
                System.out.println("没有匹配到关键字");
                return null;
        }
    }

    /**
     * 生成字段
     *
     * @param fields           所有属性
     * @param sqlBuilder       sql语句
     * @param excludeFieldList 排除字段
     * @param updateCondition  修改条件
     */
    public static void generateField(Field[] fields, StringBuilder sqlBuilder,
                                     List<String> excludeFieldList,
                                     String updateCondition) {
        int count = 0;
        Field[] var5 = fields;
        int var6 = fields.length;

        for (int var7 = 0; var7 < var6; ++var7) {
            Field field = var5[var7];
            String fieldName = field.getName();
            if (!excludeFieldList.contains(fieldName)) {
                if (count < fields.length - 1) {
                    sqlBuilder.append(humpConvert(fieldName))
                            .append(Objects.isNull(updateCondition) ? "" : updateCondition)
                            .append(SqlKeyWordEnum.COMMA.getName());
                } else {
                    sqlBuilder.append(humpConvert(fieldName))
                            .append(Objects.isNull(updateCondition) ? "" : updateCondition);
                }

                ++count;
            }
        }
        char charAt = sqlBuilder.charAt(sqlBuilder.length() - 1);
        if (SqlKeyWordEnum.COMMA.getName().equals(charAt)) {
            sqlBuilder.deleteCharAt(sqlBuilder.length() - 1);
        }

    }

    /**
     * 生成查询sql语句
     *
     * @param cls            类对象
     * @param sqlKeyWordEnum sql关键字
     * @param tableName      表名
     * @param isAllField     是否全部字段
     * @param excludeField   排除字段
     * @return
     */
    public static String selectSql(Class<?> cls, SqlKeyWordEnum sqlKeyWordEnum,
                                   String tableName, Boolean isAllField,
                                   String... excludeField) {
        attributeAssert(tableName, sqlKeyWordEnum);
        StringBuilder sqlBuilder = new StringBuilder(sqlKeyWordEnum.getName());
        List<String> excludeFieldList = new ArrayList(Arrays.asList(excludeField));
        Field[] fields = cls.getDeclaredFields();
        if (ArrayUtils.isNotEmpty(fields)) {
            if (!isAllField) {
                generateField(fields, sqlBuilder, excludeFieldList, (String) null);
            } else {
                sqlBuilder.append(SqlKeyWordEnum.ASTERISK.getName());
            }
        }

        return sqlBuilder.append(SqlKeyWordEnum.FROM.getName()).append(tableName).toString();
    }

    /**
     * 生成修改sql语句
     *
     * @param cls            类对象
     * @param sqlKeyWordEnum sql关键字
     * @param tableName      表名
     * @param excludeField   排除的字段
     * @return
     */
    public static String updateSql(Class<?> cls, SqlKeyWordEnum sqlKeyWordEnum,
                                   String tableName, String... excludeField) {
        attributeAssert(tableName, sqlKeyWordEnum);
        StringBuilder sqlBuilder = new StringBuilder(sqlKeyWordEnum.getName())
                .append(tableName).append(SqlKeyWordEnum.set.getName());
        List<String> excludeFieldList = new ArrayList(Arrays.asList(excludeField));
        Field[] fields = cls.getDeclaredFields();
        generateField(fields, sqlBuilder, excludeFieldList, SqlKeyWordEnum.QUESTION.getName());
        return sqlBuilder.toString();
    }

    /**
     * 生成插入sql语句
     *
     * @param cls            类对象
     * @param sqlKeyWordEnum sql关键字
     * @param tableName      表名
     * @param excludeField   排除的字段
     * @return
     */
    public static String insertSql(Class<?> cls, SqlKeyWordEnum sqlKeyWordEnum,
                                   String tableName, String... excludeField) {
        attributeAssert(tableName, sqlKeyWordEnum);
        StringBuilder sqlBuilder = new StringBuilder(sqlKeyWordEnum.getName())
                .append(tableName).append(SqlKeyWordEnum.LEFT_BRACKET.getName());
        List<String> excludeFieldList = new ArrayList(Arrays.asList(excludeField));
        Field[] fields = cls.getDeclaredFields();
        generateField(fields, sqlBuilder, excludeFieldList, (String) null);
        sqlBuilder.append(SqlKeyWordEnum.RIGHT_BRACKET.getName()).append(SqlKeyWordEnum.VALUES.getName());
        return sqlBuilder.toString();
    }

    /**
     * 生成删除sql语句
     *
     * @param sqlKeyWordEnum sql关键字
     * @param tableName      表名
     * @param conditionMap   条件数据
     * @return
     */
    public static String deleteSql(SqlKeyWordEnum sqlKeyWordEnum, String tableName,
                                   Map<String, List<Object>> conditionMap) {
        attributeAssert(tableName, sqlKeyWordEnum);
        StringBuilder sqlBuilder = (new StringBuilder(sqlKeyWordEnum.getName())).append(tableName);
        conditionGenerate(sqlBuilder, conditionMap);
        return sqlBuilder.toString();
    }

    /**
     * 条件生成
     *
     * @param sqlBuilder   sql语句
     * @param conditionMap 条件数据
     */
    public static void conditionGenerate(StringBuilder sqlBuilder, Map<String, List<Object>> conditionMap) {
        if (MapUtils.isNotEmpty(conditionMap)) {
            sqlBuilder.append(SqlKeyWordEnum.WHERE.getName());
            AtomicInteger count = new AtomicInteger();
            conditionMap.forEach((k, v) -> {
                k = String.valueOf(humpConvert(k));
                if (!CollectionUtils.isEmpty(v)) {
                    if (v.size() > 1) {
                        if (count.getAndIncrement() >= 1) {
                            sqlBuilder.append(SqlKeyWordEnum.AND.getName());
                        }

                        sqlBuilder.append(k).append(SqlKeyWordEnum.IN.getName()).append(SqlKeyWordEnum.LEFT_BRACKET.getName());
                        v.forEach((item) -> {
                            sqlBuilder.append(interfaceOfType(item)).append(SqlKeyWordEnum.COMMA.getName());
                        });
                        sqlBuilder.deleteCharAt(sqlBuilder.length() - 1).append(SqlKeyWordEnum.RIGHT_BRACKET.getName());
                    } else {
                        if (count.getAndIncrement() >= 1) {
                            sqlBuilder.append(SqlKeyWordEnum.AND.getName());
                        }

                        sqlBuilder.append(k).append("=").append(interfaceOfType(v.get(0)));
                    }
                }

            });
        }

    }

    /**
     * 属性校验
     *
     * @param tableName      表名
     * @param sqlKeyWordEnum sql关键字
     */
    private static void attributeAssert(String tableName, SqlKeyWordEnum sqlKeyWordEnum) {
        Assert.notBlank(tableName, "表名不能为空", new Object[0]);
        Assert.notNull(sqlKeyWordEnum, "sql 属性不能为null", new Object[0]);
    }

    /**
     * 驼峰命名转换
     *
     * @param fieldName 属性名
     */
    public static StringBuilder humpConvert(String fieldName) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < fieldName.length(); i++) {
            char c = fieldName.charAt(i);
            if (i < fieldName.length() - 1) {
                // 获取后面一个字符,判断当前字符是否为大写, 大写则在该字符前加上下划线
                if (Character.isUpperCase(c)) {
                    sb.append("_");
                }
            }
            sb.append(Character.toLowerCase(c));
        }
        return sb;
    }


    /**
     * 类型判断,并进行特殊处理
     *
     * @param type 类型
     * @param <T>
     * @return
     */
    private static <T> T interfaceOfType(T type) {
        if (type instanceof Integer) {
            return type;
        } else if (type instanceof Long) {
            return type;
        } else if (type instanceof Short) {
            return type;
        } else if (type instanceof Double) {
            return type;
        } else if (type instanceof Float) {
            return type;
        } else if (type instanceof Character) {
            return (T) ("'" + type + "'");
        } else if (type instanceof String) {
            return (T) ("'" + type + "'");
        } else if (type instanceof Date) {
            return (T) ("'" + DateUtils.dateToString((Date) type) + "'");
        } else {
            return type;
        }
    }
}
